home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
presto
/
prest1_0.lha
/
src
/
presto.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
7KB
|
285 lines
/*
* presto.c
*
* Main PRESTO bootstrapping code. Works something like this:
*
* main()
* Create a new MAIN object.
* delete the scheduler thread
* exit
*
* Main::Main()
* Call Main::init giving programmer chance to set up
* initial parameters.
*
* - Bind "thisthread" to the default thread we get from UNIX.
* - Create a new scheduler object.
* - Create a thread to run in the scheduler object.
* - Start new thread in scheduler object. We are running
* without preemption and with a single processor at this
* point, so the start just puts the thread/scheduler pair
* on the ready queue.
* - Create nummainthreads bound to Main::main and "start" them
* by placing them on the run queue. Again, we know that
* they won't run until the scheduler actually kicks in.
*
* - Invoke "thisproc" getting it to start pulling threads
* off the readyq.
*/
#define _PRESTO_C
#include <stddef.h>
#include <sys/types.h>
#include <osfcn.h>
#include <stream.h>
#include "presto.h"
Main *MAIN;
Scheduler *sched; // does not need to be shared,
// just what it references does
static int main_exit_code = 0; // how we leave
shared_t int prestoState = STATIC_CTOR;
start_Scheduler (Scheduler *s)
{
return s->invoke();
}
start_Main (Main *m)
{
return m->main ();
}
Main::Main(int ac, char **ap, char **ep)
{
argc = ac;
argv = ap;
envp = ep;
numprocessors = 1;
mainstacksizes = DEFSTACKSIZ;
nummainthreads = 1;
stacksize = DEFSTACKSIZ;
quantum = DEFQUANTUM;
#ifdef i386
affinity = 0;
#endif /* i386 */
#ifdef PROFILE
numprofilers = 1;
QInit();
#endif
}
void
Main::run ()
{
Thread *t, *mainthread;
mainthread = new Thread("_MAIN_", 0, 0); // run on same stack
mainthread->setflags(TF_SCHEDULER|TF_KEEPSTACK|TF_NONPREEMPTABLE);
//
// "thisthread" refers to the current thread of execution running
// right here, right now. Make our thread point at the static process
// object until we have our own process object to reference into.
//
mainthread->setproc(sysproc);
thisthread = mainthread;
prestoState = MAIN_INIT;
// give the programmer a chance
if (main_exit_code = Main::init()) { // non-zero return
return; // is bad news
}
#ifdef PROFILE
if ((numprocessors + numprofilers) > NUMPROCS)
{
cout << "Too many processors: " << numprocessors
<< numprofilers << "\n";
return; // is bad news
}
QBegin(numprocessors, numprofilers, affinity);
#endif
#ifdef sun
numprocessors = 1;
#endif /* sun */
#if defined(vax)
// VAX unix version runs on uniprocessors only for now.
numprocessors = 1;
#endif /* vax */
#ifdef mips
numprocessors = 1;
#endif /* mips */
if (thisthread != mainthread)
thisthread = mainthread;
prestoState = MAIN_MAIN;
//
// prime the scheduler
//
#ifdef DEBUG_STARTUP
cout << "invoking ctor for scheduler\n";
cout.flush();
#endif /* DEBUG_STARTUP */
if (sched == (Scheduler*)0)
sched = new Scheduler(numprocessors,quantum); // sets thisproc
//
// t becomes the first schedulable thread
// Since we only have one processor, and no preemption here
// we return with t on the ready q.
//
#ifdef DEBUG_STARTUP
cout << "making thread SCHEDULER_STARTER\n";
cout.flush();
#endif /* DEBUG_STARTUP */
t = mainthread->newthread ("SCHEDULER_STARTER");
t->nonpreemptable();
t->start(0, (PFany) start_Scheduler, sched);
//
// Build the main threads and readyq them
//
#ifdef DEBUG_STARTUP
cout << "making the main threads\n";
cout.flush();
#endif /* DEBUG_STARTUP */
for (int i = 0; i < nummainthreads; i++) {
char buf[8]; // lotsa threads
sprintf(buf,"%s.%d", MAINNAME, i);
char *name = new char[strlen(buf)+1];
strcpy(name, buf);
Thread *t = mainthread->newthread (name, i+1, mainstacksizes);
t->start(0, (PFany) start_Main, this);
}
// Crank up the scheduler in the context of thisthread.
// This will read the SCHEDULER thread off the
// the readyq, invoke that thread
// on the scheduler itself, which will cause the scheduler
// to then create numprocessors copies of itself (each
// running on its own stack). The SCHEDULER thread
// is guaranteed not to block and will be the first thread
// to terminate, so we can quickly reuse it.
//
//
// Bind this thread to a processor which will start up all the
// coschedulers. Thisthread will not be queued since it's a scheduler.
// We have to start it up directly.
//
#ifdef DEBUG_STARTUP
cout << "about to start scheduler\n"; cout.flush ();
cout.flush();
#endif /* DEBUG_STARTUP */
mainthread->isrunning();
thisproc->invoke(); // start thisproc which will start
// the scheduler thread which will
// start all the processor threads
// which will then pull the main
// threads off the readyq
mainthread->isnotrunning();
//
// Since shutdown is not synchronized, there is a race condition which
// can result in sched getting deleted while process objects are still
// active. If it hurts, don't do it.
//
// if (sched)
// delete sched;
//
delete thisproc;
thisproc = sysproc;
//delete thisthread; /* done in runrun */
//thisthread = 0;
//
// Threads are out... thisthread is undefined at this point
//
// should be single unix process by now
cout << "HALT" << endl << flush;
prestoState = MAIN_DONE;
main_exit_code = Main::done();
}
Main::~Main()
{
}
//
// Preallocate tons of threads in the parent process's address space.
// This is a temporary hack to get around the brain-damaged sequent
// shared memory implementation.
//
// NOTE: not called from anywhere in Presto.
//
int
Main::preallocthreads(int cnt, int sz)
{
int j;
j = cnt;
Thread **tlist = new Thread*[j];
while (j--) {
tlist[j] = thisthread->newthread ("any",
0, // any id
sz); // stack size
}
j = cnt;
while (j--) {
delete tlist[j];
}
delete tlist;
return cnt;
}
typedef void (*PF)();
extern PF set_new_handler(PF);
extern void failed_malloc();
void
main(int argc, char **argv, char **envp)
{
set_new_handler(failed_malloc);
//
// Create a new main thread.
//
MAIN = new Main(argc, argv, envp);
MAIN->run ();
if (MAIN)
delete MAIN;
prestoState = STATIC_DTOR;
while (wait(0) != -1) // collect kids, get execution stats
continue;
#ifdef __DECCXX
/* cxx has a wierd effect that shows up during the
static destructor calls that occur during an exit().
calling _exit() avoids this, but the problem
needs resolving.
*/
_exit(main_exit_code);
#else
exit (main_exit_code);
#endif /* __DECCXX */
}